package com.adcc.loadSheetForwarder.utils;

import com.adcc.loadSheetForwarder.configuration.UmeTripProperties;
import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpStatus;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.util.List;
import java.util.Map;


/**
 * 接口调用工具类
 */
@Component
@Slf4j
public class RestClient {
    @Autowired
    UmeTripProperties properties;

    /**
     * 调用航旅接口获取数据(map形式)
     *
     * @param url
     * @param map
     * @return
     */
    @SuppressWarnings({"unchecked"})
    public Map<String, Object> umeJsonStringPost(String url, Map<String, Object> map) {
        String traceid = (String) map.get("traceid");
        log.info(String.format("url:%s,params:%s", url, JSON.toJSONString(map)));
        CloseableHttpClient client = null;
        CloseableHttpResponse response = null;
        try {
            client = getHttpClient(url.startsWith("https"));
            HttpPost post = new HttpPost(url);
            RequestConfig config = RequestConfig.custom()
                    .setSocketTimeout(properties.getSocketTimeout())
                    .setConnectTimeout(properties.getConnectTimeout())
                    .setConnectionRequestTimeout(properties.getConnectionRequestTimeout()).build();
            post.addHeader("Content-Type", "application/json;charset=UTF-8");
            post.addHeader("Accept", "application/json");
            if (map != null && map.size() > 0) {
                StringEntity entity = new StringEntity(JSON.toJSONString(map), StandardCharsets.UTF_8);
                post.setEntity(entity);
            }
            post.setConfig(config);
            response = client.execute(post);
            if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                String responseStr = EntityUtils.toString(response.getEntity());
                log.info(String.format("traceid:%s,response data:%s", traceid, responseStr));
                return JSON.parseObject(responseStr, Map.class);
            } else {
                log.error(String.format("traceid:%s,response status:%s", traceid, response.getStatusLine().getStatusCode()));
                Map<String, Object> errorMap = Maps.newHashMap();
                errorMap.put(SystemConst.REST_CLIENT_ERROR_KEY, ResultCode.UME_RETURN_DATA_ERROR);
                return errorMap;
            }
        } catch (ConnectTimeoutException e) {
            log.error(String.format("traceid:%s,umeJsonStringPost() error", traceid), e);
            Map<String, Object> errorMap = Maps.newHashMap();
            errorMap.put(SystemConst.REST_CLIENT_ERROR_KEY, ResultCode.UME_TIMEOUT_ERROR);
            return errorMap;
        } catch (Exception e) {
            log.error(String.format("traceid:%s,umeJsonStringPost() error", traceid), e);
            Map<String, Object> errorMap = Maps.newHashMap();
            errorMap.put(SystemConst.REST_CLIENT_ERROR_KEY, ResultCode.SERVER_ERROR);
            return errorMap;
        } finally {
            if (response != null) {
                try {
                    response.close();
                } catch (IOException ex) {
                }
            }
            if (client != null) {
                try {
                    client.close();
                } catch (IOException ex) {
                }
            }
        }
    }

    /**
     * 调用航旅接口获取数据(key-value形式)
     *
     * @param url
     * @param map
     * @return
     */
    @SuppressWarnings({"unchecked"})
    public Map<String, Object> umeKeyValuePost(String url, Map<String, Object> map) {
        String traceid = (String) map.get("traceid");
        log.info(String.format("url:%s,params:%s", url, JSON.toJSONString(map)));
        CloseableHttpClient client = null;
        CloseableHttpResponse response = null;
        try {
            client = getHttpClient(url.startsWith("https"));
            HttpPost post = new HttpPost(url);
            RequestConfig config = RequestConfig.custom()
                    .setSocketTimeout(properties.getSocketTimeout())
                    .setConnectTimeout(properties.getConnectTimeout())
                    .setConnectionRequestTimeout(properties.getConnectionRequestTimeout()).build();
            post.addHeader("Content-Type", "application/json;charset=UTF-8");
            post.addHeader("Accept", "application/json");
            post.setConfig(config);

            List<BasicNameValuePair> paramList = Lists.newArrayList();
            for (Map.Entry<String, Object> entry : map.entrySet()) {
                paramList.add(new BasicNameValuePair(entry.getKey(), String.valueOf(entry.getValue())));
            }
            if (!paramList.isEmpty()) {
                UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList, StandardCharsets.UTF_8);
                post.setEntity(entity);
            }
            response = client.execute(post);
            if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                String responseStr = EntityUtils.toString(response.getEntity());
                log.info(String.format("traceid:%s,response data:%s", traceid, responseStr));
                return JSON.parseObject(responseStr, Map.class);
            } else {
                log.error(String.format("traceid:%s,response status:%s", traceid, response.getStatusLine().getStatusCode()));
                Map<String, Object> errorMap = Maps.newHashMap();
                errorMap.put(SystemConst.REST_CLIENT_ERROR_KEY, ResultCode.UME_RETURN_DATA_ERROR);
                return errorMap;
            }
        } catch (ConnectTimeoutException e) {
            log.error(String.format("traceid:%s,umeKeyValuePost() error", traceid), e);
            Map<String, Object> errorMap = Maps.newHashMap();
            errorMap.put(SystemConst.REST_CLIENT_ERROR_KEY, ResultCode.UME_TIMEOUT_ERROR);
            return errorMap;
        } catch (Exception e) {
            log.error(String.format("traceid:%s,umeKeyValuePost() error", traceid), e);
            Map<String, Object> errorMap = Maps.newHashMap();
            errorMap.put(SystemConst.REST_CLIENT_ERROR_KEY, ResultCode.SERVER_ERROR);
            return errorMap;
        } finally {
            if (response != null) {
                try {
                    response.close();
                } catch (IOException ex) {
                }
            }
            if (client != null) {
                try {
                    client.close();
                } catch (IOException ex) {
                }
            }
        }
    }

    /**
     * 创建HttpClient客户端
     *
     * @param isHttps
     * @return
     */
    private CloseableHttpClient getHttpClient(boolean isHttps) {
        CloseableHttpClient httpClient;
        if (isHttps) {
            SSLConnectionSocketFactory sslSocketFactory;
            try {
                sslSocketFactory = createIgnoreVerifySSLFactory();
            } catch (Exception e) {
                log.error("createIgnoreVerifySSLFactory() error", e);
                throw new RuntimeException("createIgnoreVerifySSLFactory error");
            }
            httpClient = HttpClientBuilder.create().setSSLSocketFactory(sslSocketFactory).build();
            return httpClient;
        }
        httpClient = HttpClientBuilder.create().build();
        return httpClient;
    }

    /**
     * 绕过ssl验证
     *
     * @return
     * @throws NoSuchAlgorithmException
     * @throws KeyManagementException
     */
    private SSLConnectionSocketFactory createIgnoreVerifySSLFactory() throws NoSuchAlgorithmException, KeyManagementException {
        SSLContext sc = SSLContext.getInstance("SSLv3");
        // 实现一个X509TrustManager接口，用于绕过验证
        X509TrustManager trustManager = new X509TrustManager() {
            @Override
            public void checkClientTrusted(
                    java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
                    String paramString) throws CertificateException {
            }

            @Override
            public void checkServerTrusted(
                    java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
                    String paramString) throws CertificateException {
            }

            @Override
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                return null;
            }
        };
        sc.init(null, new TrustManager[]{trustManager}, null);
        return new SSLConnectionSocketFactory(sc);
    }
}
